/* ------------------------------------------------------------------------*
 *
 * ------------------------------------------------------------------------*/
#include "bsp.h"
#include "stdint.h"
#include "os_obj.h"
#include "block_mix_log.h"
#include "str_ext.h"
#include "framework.h"
#include "nor_cmd.h"
#include "lut\nand_lut.h"

/*****************************************************************************
 * @brief   delay .
 *****************************************************************************/
extern nand_lut_type nand_dev;

static void LogErase(uint32_t AddrBase);							/*从指定地址擦除，Nums指定擦除的扇区个数*/
static void LogProgram(uint32_t Addr, uint8_t *Data, uint16_t Len); /*向指定指定地址编程数据*/
static void LogRead(uint32_t Addr, uint8_t *Data, uint16_t Len);	/*读取块数据*/
static void LogFlashFullCallBack(uint8_t mode);						/*存满回调*/

int32_t log_blk_iter_back(int32_t site, uint8_t *dat);
static char power_off_sim = 0;
static int tim = 0;
static int wrcnt = 0;
////////////////////////////////////////////////////////////////////////////////
// 日志缓存配置

////////////////////////////////////////////////////////////////////////////////
static void BlkProgram(uint32_t Addr);
static void BlkRead(uint32_t Addr, uint16_t Len, uint8_t *Data);
static void BlkErase(uint32_t AddrBase);
block_mix_log_api_ref(mblk_log_cfg);
mix_log_buff_info_type mix_buff_info;
block_mix_log_info_type mblk_log_info;
const block_mix_log_cfg_type mblk_log_cfg = {
	.block_amount = 20,
	.block_base = NAND_BASE_BLOCK_MIX_LOG,
	.Info = &mblk_log_info,
	.buf_cfg = {
		.buff_amount = 8,
		.first_base = SWNOR_BASE_MIX_LOG_BUFF,
		.buff_size = 128 * 1024,
		.page_size = 4 * 1024,
		.log_size_max = 128,
		.info = &mix_buff_info,
		.erase = LogErase,
		.program = LogProgram,
		.read = LogRead,	
	},
	.erase = BlkErase,
	.program = BlkProgram,
	.read = BlkRead,
	.api = block_mix_log_api_name(mblk_log_cfg)};
block_mix_log_api_make(mblk_log_cfg);

void bmix_init_auto(void)
{
	mblk_log_cfg.api->buf_init();
	mblk_log_cfg.api->init();
}
// obj_init_order5(bmix_init_auto);

/*******************************************************************************
 * @brief: 初始化
 * @param cfg
 * @return {*}
 ******************************************************************************/
int bmix_log_init(int argc, char **argv)
{
	mblk_log_cfg.api->buf_init();
	mblk_log_cfg.api->init();

	dbg_print("log buf info: base %dKB, page: %d, sub: %d, addr off:%d" PTCR,
			  (mblk_log_cfg.buf_cfg.info->flash_base - mblk_log_cfg.buf_cfg.first_base) >> 10,
			  mblk_log_cfg.buf_cfg.info->page_now,
			  mblk_log_cfg.buf_cfg.info->site_next,
			  mblk_log_cfg.buf_cfg.info->dat_addr_last);
	dbg_print("blk info: start %d, next %d \n", mblk_log_cfg.Info->block_start, mblk_log_cfg.Info->block_next);

	mblk_log_cfg.Info->save_cnt = 0;

	dbg_puts(SYMBOL_LINE_EQ PTCR);
	return 0;
}
DBG_FUN_EXPORT(bmix_log_init);

/*******************************************************************************
 * @brief: 清除
 * @param cfg
 * @return {*}
 ******************************************************************************/
int bmix_log_clr(int argc, char **argv)
{
	loop(mblk_log_cfg.buf_cfg.buff_size / mblk_log_cfg.buf_cfg.page_size * mblk_log_cfg.buf_cfg.buff_amount)
	{
		LogErase(mblk_log_cfg.buf_cfg.first_base + index * mblk_log_cfg.buf_cfg.page_size);
	}

	loop(mblk_log_cfg.block_amount)
	{
		BlkErase(mblk_log_cfg.block_base + index);
	}

	mblk_log_cfg.api->buf_init();
	mblk_log_cfg.api->init();

	tim = 0;
	wrcnt = 0;

	dbg_puts("clear end" PTCR);
	dbg_puts(SYMBOL_LINE_EQ PTCR);

	return 0;
}
DBG_FUN_EXPORT(bmix_log_clr);

/*******************************************************************************
 * @brief: 存储
 * @param cfg
 * @return {*}
 ******************************************************************************/
int bmix_log_save(int argc, char **argv)
{
	int cnt = 1;
	uu08 buff[128] = "mix log dat:";
	static int dir = 1;
	static int len = 20;

	if (argc > 1)
		cnt = atoi(argv[1]);

	if (argc > 2)
		tim = atoi(argv[2]);

	// 保存日志
	while (cnt--)
	{
		if (dir)
		{
			var_loop_inc(len, 20, 40);
		}
		else
		{
			var_loop_dec(len, 20, 40);
		}
		if (20 == len)
			dir = 1;
		if (40 == len)
			dir = 0;

		copy_str("mix log dat:", buff, 128);
		sprintf((char *)buff, "log:%-8d", wrcnt);
		memset(&buff[strlen((char *)buff)], '+', len - strlen((char *)buff));
		buff[len] = 0;
		mblk_log_cfg.api->buf_save(tim, buff, len);
		tim += 5;
		wrcnt++;
	}

	dbg_puts("save end" PTCR);
	dbg_puts(SYMBOL_LINE_EQ PTCR);

	return 0;
}
DBG_FUN_EXPORT(bmix_log_save);

/*******************************************************************************
 * @brief: 读取
 * @param cfg
 * @return {*}
 ******************************************************************************/
int bmix_log_buf_read(int argc, char **argv)
{
	mix_log_obj_type ld;
	int cnt = 1;

	if (argc > 1)
		ld.page_site = atoi(argv[1]);

	if (argc > 2)
		ld.sub_site = atoi(argv[2]);

	if (argc > 3)
		cnt = atoi(argv[3]);

	ld.dat = (uu8 *)malloc(4000);

	// 保存日志
	loop(cnt)
	{
		mblk_log_cfg.api->buf_read(&ld);

		if (ld.log_head.tim == U32_MAX)
		{
			if (ld.sub_site == 0)
				break;
			else
			{
				ld.sub_site = 0;
				ld.page_site++;
				if (ld.page_site >= mblk_log_cfg.buf_cfg.info->page_amount)
					break;
				else
					continue;
			}
		}

		ld.dat[ld.log_head.len] = 0;
		dbg_print("tim: %8d, addr: %4d, len: %4d, dat: %s" PTCR, ld.log_head.tim, ld.log_head.addr, ld.log_head.len, ld.dat);

		ld.sub_site++;
	}

	free(ld.dat);

	dbg_puts(SYMBOL_LINE_EQ PTCR);

	return 0;
}
DBG_FUN_EXPORT(bmix_log_buf_read);

/*--------------------------------------------------------------------------------*
 * log buff hal
 *--------------------------------------------------------------------------------*/
void LogProgram(uint32_t Addr, uint8_t *Data, uint16_t Len)
{
	nor_write_multi(Addr, Len, (uu8 *)Data);
}

void LogRead(uint32_t Addr, uint8_t *Data, uint16_t Len)
{
	nor_read(Addr, Len, (uu8 *)Data);
}

void LogErase(uint32_t AddrBase)
{
	nor_sector_erase(AddrBase);
}

void LogFlashFullCallBack(uint8_t mode)
{
	dbg_print("log buffer full call back \n");

	mblk_log_cfg.api->save();

	dbg_print("blk info: start %d, next %d \n", mblk_log_cfg.Info->block_start, mblk_log_cfg.Info->block_next);

	if (power_off_sim)
	{
		osDelay(10);
		NVIC_SystemReset();
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static uint8_t log_dat_get(nand_lut_type *lut, uint32_t addr_offset, uint8_t *pdat, uint16_t len)
{
	nor_read(mblk_log_cfg.buf_cfg.info->flash_base + addr_offset,
			 len,
			 (uu8 *)pdat);

	return 0;
}

void BlkProgram(uint32_t blk)
{
	nand_dev.api.block_write(blk, log_dat_get);

	/*
	uu8 *buff = malloc(mblk_log_cfg.buf->page_size);

	nor_block_erase(blk * 32 * 1024);

	loop(mblk_log_cfg.buf->buff_size / mblk_log_cfg.buf->page_size)
	{
		nor_read(mblk_log_cfg.buf->info->flash_base + index * mblk_log_cfg.buf->page_size,
				 mblk_log_cfg.buf->page_size,
				 (uu8 *)buff);

		nor_write_multi(blk * 32 * 1024 + index * mblk_log_cfg.buf->page_size,
						mblk_log_cfg.buf->page_size,
						(uu8 *)buff);
	}

	free(buff);
	*/

	dbg_print("block write : %d" PTCR, blk - mblk_log_cfg.block_base);
}

void BlkRead(uint32_t Addr, uint16_t Len, uint8_t *Data)
{
	nand_dev.api.addr_read(Addr, Len, Data);
	// nor_read(Addr, Len, (uu8 *)Data);
}

void BlkErase(uint32_t blk)
{
	nand_dev.api.block_erase(blk);
	// nor_block_erase(blk * 32 * 1024);
}

static int32_t log_iter_back(mix_log_obj_type *obj)
{
	uu08 dattail;

	dattail = obj->dat[obj->log_head.len];
	obj->dat[obj->log_head.len] = 0;
	dbg_print("log tm: %8d, page=%02d-%02d, sit=%3d, log len:%3d, dat: %s" PTCR,
			  obj->log_head.tim,
			  obj->page_site / mblk_log_cfg.buf_cfg.info->page_amount, obj->page_site % mblk_log_cfg.buf_cfg.info->page_amount,
			  obj->sub_site,
			  obj->log_head.len,
			  (char *)obj->dat);

	obj->dat[obj->log_head.len] = dattail;

	return 1;
}

int bmix_log_siter(int argc, char **argv)
{
	mix_log_obj_type logr;
	mix_log_obj_type start;
	mix_log_obj_type end;
	int num;
	UU16 flag = 0xFFFF;

	uu8 buff[128];

	if (argc < 5)
		return 1;

	if (argc >= 6)
		flag = atoi(argv[5]);

	start.page_site = atoi(argv[1]);
	start.sub_site = atoi(argv[2]);

	end.page_site = atoi(argv[3]);
	end.sub_site = atoi(argv[4]);

	logr.dat = buff;
	num = mblk_log_cfg.api->site_iter(&start, &end, log_iter_back);

	dbg_print("site iter %d" PTCR, num);

	return 0;
}
DBG_FUN_EXPORT(bmix_log_siter);

int bmix_log_titer(int argc, char **argv)
{
	uint32_t log_stm, log_etm, num;

	if (argc < 3)
		return 1;

	log_stm = atoi(argv[1]);
	log_etm = atoi(argv[2]);

	num = mblk_log_cfg.api->time_iter(log_stm, log_etm, log_iter_back);

	dbg_print("time iter %d" PTCR, num);

	return 0;
}
DBG_FUN_EXPORT(bmix_log_titer);

int bmix_log_power_sim(int argc, char **argv)
{
	power_off_sim = 1;

	dbg_print("power down sim req, please save data" PTCR);

	return 0;
}
DBG_FUN_EXPORT(bmix_log_power_sim);
